package com.tripleying.dogend.dnfipm.controller;

import com.google.gson.JsonObject;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXCheckBox;
import com.jfoenix.controls.JFXListView;
import com.jfoenix.controls.JFXPopup;
import com.jfoenix.controls.JFXPopup.PopupHPosition;
import com.jfoenix.controls.JFXPopup.PopupVPosition;
import com.jfoenix.controls.JFXTextField;
import com.tripleying.dogend.dnfipm.App;
import com.tripleying.dogend.dnfipm.model.NPKCell;
import com.tripleying.dogend.dnfipm.model.NPKItem;
import com.tripleying.dogend.dnfipm.util.FileUtil;
import com.tripleying.dogend.dnfipm.util.HTTPUtil;
import com.tripleying.dogend.dnfipm.util.MessageUtil;
import com.tripleying.dogend.dnfipm.util.NPKUtil;
import java.awt.Desktop;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

/**
 * 主界面
 * @author Dogend
 */
public class MainController {

    private double x; 
    private double y;
    private double x_stage;
    private double y_stage;
    private Image baseBg;
    // 列表状态
    private ListStatus status;
    private final Stage stage;
    // 设置的DNF的补丁文件夹
    private final File folder;
    // 真实补丁列表
    private final Map<String, NPKCell> npkol;
    private static MainController mc;
    // 窗口标题
    @FXML
    private Label title;
    // 背景
    @FXML
    private ImageView bg;
    // 列表标题
    @FXML
    private Label listTitle;
    // 列表
    @FXML
    private JFXListView list;
    // 搜索框
    @FXML
    private JFXTextField search;
    @FXML
    private JFXCheckBox filter;
    @FXML
    private JFXButton more;
    private final JFXPopup popup;
    
    public MainController(){
        mc = this;
        stage = App.getStage();
        folder = App.getFolder();
        npkol = new LinkedHashMap();
        JFXListView moreList = new JFXListView();
        this.popup = new JFXPopup(moreList);
        moreList.setOnMouseClicked(e -> popup.hide());
        moreList.setPrefWidth(180);
        moreList.setPrefHeight(410);
        moreList.setOrientation(Orientation.VERTICAL);
        moreList.getItems().add(MessageUtil.createButton("打开补丁目录", 16, 30, 153, null, "customBtn", e -> openFolder()));
        moreList.getItems().add(MessageUtil.createButton("重选补丁目录", 16, 30, 153, null, "customBtn", e -> resetFolder()));
        moreList.getItems().add(MessageUtil.createButton("选择背景图片", 16, 30, 153, null, "customBtn", e -> selectBackgroundImage()));
        moreList.getItems().add(MessageUtil.createButton("随机背景目录", 16, 30, 153, null, "customBtn", e -> selectBackgroundFolder()));
        moreList.getItems().add(MessageUtil.createButton("随机更换背景", 16, 30, 153, null, "customBtn", e -> changeBackground()));
        moreList.getItems().add(MessageUtil.createButton("检查版本更新", 16, 30, 154, null, "customBtn", e -> checkUpdate()));
        moreList.getItems().add(MessageUtil.createButton("工具官方网站", 16, 30, 153, null, "customBtn", e -> openWebsite()));
        moreList.getItems().add(MessageUtil.createButton("删除所有补丁", 16, 30, 153, null, "deleteBtn", e -> allDelete()));
    }
    
    /**
     * 保存当前启用的补丁为个性化文件
     */
    @FXML
    private void addCustomConfig(){
        loadNPK();
        List<String> l = new ArrayList();
        if(ListStatus.NPKList.equals(status)){
            npkol.values().forEach(cell -> {
                if(cell.getSwitchStatus()){
                    l.add(cell.getNPKItem().getName());
                }
            });
        }
        if(l.isEmpty()){
            MessageUtil.alertSimpleMessage("错误", "需要至少启动一个补丁才可创建个性化配置", "关闭");
        }else{
            MessageUtil.alertInputMessage("输入:", "输入要保存的个性化名称", "", "确定", "取消", str -> {
                if(str.trim().length()==0){
                    MessageUtil.alertSimpleMessage("错误", "个性化名称不能为空", "关闭");
                }else{
                    String name = str.trim();
                    if(FileUtil.saveCustom(name, l)){
                        MessageUtil.alertSimpleMessage("成功", "个性化文件创建成功", "关闭");
                    }else{
                        MessageUtil.alertSimpleMessage("错误", "个性化文件创建失败", "关闭");
                    }
                }
            });
        }
    }
    
    /**
     * 禁用所有补丁
     */
    @FXML
    private void allDisable(){
        loadNPK();
        if(ListStatus.NPKList.equals(status)){
            npkol.values().forEach(cell -> cell.disableNPK());
        }
        searchNPK();
        updateListTitle();
    }
    
    /**
     * 删除所有补丁
     */
    @FXML
    private void allDelete(){
        JFXButton btn = new JFXButton("确定");
        btn.getStyleClass().add("dialog-warning");
        btn.setOnAction(e -> {
            search.setText("");
            loadNPK();
            npkol.values().forEach(cell -> cell.getNPKItem().deleteFile());
            loadNPK();
            MessageUtil.alertSimpleMessage("成功", "已执行完删除操作, 请重新查看", "关闭");
        });
        MessageUtil.alertConfirmMessage("警告", "请慎重, 该操作不可逆, 确认继续吗？\n请尝试搜索sprite查看是否有官方文件被误搜到了", "关闭", btn);
    }
    
    /**
     * 更新列表标题
     */
    public void updateListTitle(){
        if(ListStatus.NPKList.equals(status) || ListStatus.NPKEmpty.equals(status)){
            listTitle.setText("补丁列表 ("+npkol.values().stream().filter(npk -> npk.getSwitchStatus()).count()+"/"+npkol.size()+")");
        }
    }
    
    /**
     * 向列表中加载补丁文件
     */
    @FXML
    public void loadNPK(){
        ObservableList ol = list.getItems();
        ol.clear();
        npkol.clear();
        int enNPK = 0;
        for(File file:folder.listFiles()){
            NPKItem npk = new NPKItem(file);
            if(npk.isValidate()){
                NPKCell cell = new NPKCell(npk);
                npk.getDeleteButton().setOnAction(e -> {
                    if(npk.deleteFile()){
                        npkol.remove(npk.getName());
                        ol.remove(cell);
                    }else{
                        MessageUtil.alertSimpleMessage("错误", "文件删除失败", "关闭");
                    }
                    updateListTitle();
                });
                npkol.put(npk.getName(), cell);
                if(cell.getSwitchStatus()) enNPK++;
            }
        }
        listTitle.setText("补丁列表 ("+enNPK+"/"+npkol.size()+")");
        if(npkol.isEmpty()){
            status = ListStatus.NPKEmpty;
            Label l = new Label("您还没有安装任何补丁!");
            l.setFont(new Font(20));
            l.setPrefHeight(450);
            l.setPrefWidth(550);
            l.setTextFill(Color.RED);
            l.setAlignment(Pos.CENTER);
            ol.add(l);
        }else{
            status = ListStatus.NPKList;
            searchNPK();
        }
    }
    
    @FXML
    private void searchNPK(){
        searchNPK(search.getText().trim());
    }
    
    /**
     * 搜索
     * @param txt 搜索内容
     */
    private void searchNPK(String txt){
        ObservableList ol = list.getItems();
        ol.clear();
        boolean enable = filter.isSelected();
        if(Objects.equals("", txt)){
            if(enable){
                npkol.values().forEach(c -> {
                    if(c.getTruthStatus()){
                        ol.add(c);
                    }
                });
            }else{
                ol.addAll(npkol.values());
            }
        }else{
            String key = txt.toUpperCase();
            if(enable){
                npkol.forEach((name, cell) -> {
                    if(cell.getTruthStatus() && cell.getUpperName().contains(key)){
                        ol.add(cell);
                    }
                });
            }else{
                npkol.forEach((name, cell) -> {
                    if(cell.getUpperName().contains(key)){
                        ol.add(cell);
                    }
                });
            }
        }
        if(ol.isEmpty()){
            status = ListStatus.NPKEmpty;
            Label l = new Label("没有搜索到任何补丁!");
            l.setFont(new Font(20));
            l.setPrefHeight(450);
            l.setPrefWidth(550);
            l.setTextFill(Color.RED);
            l.setAlignment(Pos.CENTER);
            ol.add(l);
        }else{
            status = ListStatus.NPKList;
        }
    }
    
    /**
     * 通过文件选择器添加补丁文件
     */
    @FXML
    public void addNPK(){
        FileChooser fc = new FileChooser();
        fc.getExtensionFilters().add(new FileChooser.ExtensionFilter("NPK补丁或压缩包 (.npk/.zip/.rar/.7z)", "*.npk", "*.zip", "*.rar", "*.7z"));
        fc.setTitle("请选择NPK补丁文件, 或包含补丁文件的压缩包");
        List<File> fl = fc.showOpenMultipleDialog(stage);
        if(fl!=null && !fl.isEmpty()){
            addNPKFile(fl);
            loadNPK();
        }
    }
    
    /**
     * 向列表中加载个性化文件
     */
    @FXML
    public void loadCustom(){
        ObservableList ol = list.getItems();
        ol.clear();
        File cfolder = new File(FileUtil.getFolder(), "custom");
        if(cfolder.exists()){
            for(File file:cfolder.listFiles()){
                String name = file.getName();
                String cname = name.substring(0, name.length()-4);
                Label hb1 = new Label(cname);
                hb1.setAlignment(Pos.CENTER_LEFT);
                hb1.setPrefWidth(250);
                hb1.setMaxWidth(250);
                JFXButton hb2 = new JFXButton("应用");
                hb2.setAlignment(Pos.CENTER);
                hb2.setPrefWidth(50);
                hb2.setPrefHeight(25);
                hb2.getStyleClass().add("customBtn");
                hb2.setOnAction(e -> {
                    List<String> l = FileUtil.getCustom(cname);
                    if(l.isEmpty()){
                        MessageUtil.alertSimpleMessage("错误", "读取个性化文件失败", "关闭");
                    }else{
                        loadNPK();
                        npkol.values().forEach(cell -> {
                            if(l.contains(cell.getNPKItem().getName())){
                                cell.enableNPK();
                            }
                        });
                        searchNPK();
                        updateListTitle();
                    }
                });
                JFXButton hb3 = new JFXButton("仅应用");
                hb3.setAlignment(Pos.CENTER);
                hb3.setPrefWidth(75);
                hb3.setPrefHeight(25);
                hb3.getStyleClass().add("customBtn");
                hb3.setOnAction(e -> {
                    List<String> l = FileUtil.getCustom(cname);
                    if(l.isEmpty()){
                        MessageUtil.alertSimpleMessage("错误", "读取个性化文件失败", "关闭");
                    }else{
                        loadNPK();
                        allDisable();
                        npkol.values().forEach(cell -> {
                            if(l.contains(cell.getNPKItem().getName())){
                                cell.enableNPK();
                            }
                        });
                        searchNPK();
                        updateListTitle();
                    }
                });
                JFXButton hb4 = new JFXButton("编辑");
                hb4.setAlignment(Pos.CENTER);
                hb4.setPrefWidth(50);
                hb4.setPrefHeight(25);
                hb4.getStyleClass().add("editBtn");
                hb4.setOnAction(e -> openFile(file));
                JFXButton hb5 = new JFXButton("改名");
                hb5.setAlignment(Pos.CENTER);
                hb5.setPrefWidth(50);
                hb5.setPrefHeight(25);
                hb5.getStyleClass().add("editBtn");
                hb5.setOnAction(e -> renameCustom(cname));
                JFXButton hb6 = new JFXButton("删除");
                hb6.setAlignment(Pos.CENTER);
                hb6.setPrefWidth(50);
                hb6.setPrefHeight(25);
                hb6.getStyleClass().add("deleteBtn");
                HBox hb = new HBox(hb1,hb2,hb3,hb4,hb5,hb6);
                hb6.setOnAction(e -> {
                    if(file.exists() && !file.delete()){
                        MessageUtil.alertSimpleMessage("错误", "读取个性化文件失败", "关闭");
                    }else{
                        ol.remove(hb);
                    }
                    loadCustom();
                });
                hb.setAlignment(Pos.CENTER_LEFT);
                hb.setSpacing(10);
                ol.add(hb);
            }
        }
        listTitle.setText("个性化列表 ("+ol.size()+")");
        if(ol.isEmpty()){
            status = ListStatus.CustomEmpty;
            Label l = new Label("您还没有保存个性化配置!");
            l.setAlignment(Pos.CENTER);
            ol.add(l);
        }else{
            status = ListStatus.CustomList;
        }
    }
    
    /**
     * 重命名个性化文件
     * @param oldname 旧文件名
     */
    private void renameCustom(String oldname){
        File oldfile = new File(FileUtil.getFolder(), "custom/"+oldname+".txt");
        if(!oldfile.exists()){
            MessageUtil.alertSimpleMessage("错误", "查询不到个性化文件", "关闭");
            return;
        }
        MessageUtil.alertInputMessage("输入:", "输入要修改的个性化名称", oldname, "确定", "取消", str -> {
            if(str.trim().length()==0){
                MessageUtil.alertSimpleMessage("错误", "个性化名称不能为空", "关闭");
            }else{
                String name = str.trim();
                File newfile = new File(FileUtil.getFolder(), "custom/"+name+".txt");
                if(newfile.exists()){
                    MessageUtil.alertSimpleMessage("错误", "目标个性化名称已存在", "关闭");
                    return;
                }
                if(oldfile.renameTo(newfile)){
                    MessageUtil.alertSimpleMessage("成功", "个性化文件名修改成功", "关闭");
                }else{
                    MessageUtil.alertSimpleMessage("错误", "个性化文件名修改失败", "关闭");
                }
                loadCustom();
            }
        });
    }
    
    public void updateSearchNPK(NPKItem npk){
        if(filter.isSelected() && ListStatus.NPKList.equals(status)){
            ObservableList ol = list.getItems();
            for (Iterator it = ol.iterator(); it.hasNext();) {
                Object o = it.next();
                NPKCell c = (NPKCell)o;
                if(c.getNPKItem()==npk){
                    if(!c.getSwitchStatus()) ol.remove(o);
                    break;
                }
            }
        }
    }
    
    @FXML
    private void clearSearch(){
        search.setText("");
    }
    
    @FXML
    private void dragFile(DragEvent e){
        e.acceptTransferModes(TransferMode.ANY);
    }
    
    /**
     * 通过向列表拖拽文件添加补丁
     * @param e 事件
     */
    @FXML
    private void draggedFile(DragEvent e){
        Dragboard db = e.getDragboard();
        if (db.hasFiles()){
            addNPKFile(db.getFiles());
            loadNPK();
        }
    }
    
    /**
     * 两种添加补丁的方式获取文件列表后通过此方法添加补丁
     * @param fl 文件列表
     */
    private void addNPKFile(List<File> fl){
        if(fl!=null && !fl.isEmpty()){
            NPKUtil.addNPKFiles(fl);
        }else{
            MessageUtil.alertSimpleMessage("错误", "未选择有效的文件", "关闭");
        }
    }
    
    /**
     * 打开设置的补丁文件夹
     */
    @FXML
    private void openFolder(){
        openFile(folder);
    }
    
    /**
     * 模拟windows打开文件
     * @param file 文件
     */
    private void openFile(File file){
        try {
            String[] cmd = new String[5];
            cmd[0] = "cmd";
            cmd[1] = "/c";
            cmd[2] = "start";
            cmd[3] = " ";
            cmd[4] = file.getAbsolutePath();
            Runtime.getRuntime().exec(cmd);
        } catch (IOException ex) {
            Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    /**
     * 重设DNF补丁文件夹
     * @throws IOException 
     */
    @FXML
    private void resetFolder(){
        stage.hide();
        try {
            App.switchSelect();
        } catch (IOException ex) {
            Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    @FXML
    private void showPopup(){
        popup.show(more, PopupVPosition.BOTTOM, PopupHPosition.LEFT);
    }
    
    private void openWebsite(){
        Desktop d = Desktop.getDesktop();
        try {
            d.browse(new URI("http://qwq.tripleying.com/others/dnfipm"));
        } catch (Exception ex) {
            System.out.println(ex);
        }
    }
    
    public void selectBackgroundImage(){
        FileChooser fc = new FileChooser();
        fc.getExtensionFilters().add(new FileChooser.ExtensionFilter("所有图片", "*.*"));
        fc.setTitle("请选择图片");
        String bgs = FileUtil.getConfig("bg");
        if(bgs!=null){
            File file = new File(bgs);
            if(file.exists()){
                if(file.isDirectory()){
                    fc.setInitialDirectory(file);
                }else{
                    fc.setInitialDirectory(file.getParentFile());
                }
            }
        }
        File file = fc.showOpenDialog(App.getStage());
        if(file!=null && file.exists()){
            FileUtil.saveConfig("bg", file.getAbsolutePath());
            changeBackground();
        }
    }
    
    public void selectBackgroundFolder(){
        DirectoryChooser dc = new DirectoryChooser();
        dc.setTitle("选择存放图片的文件夹");
        String bgs = FileUtil.getConfig("bg");
        if(bgs!=null){
            File file = new File(bgs);
            if(file.exists()){
                if(file.isDirectory()){
                    dc.setInitialDirectory(file);
                }else{
                    dc.setInitialDirectory(file.getParentFile());
                }
            }
        }
        File file = dc.showDialog(stage);
        if(file!=null && file.exists()){
            FileUtil.saveConfig("bg", file.getAbsolutePath());
            changeBackground();
        }
    }
    
    public void changeBackground(){
        boolean success = false;
        String bgs = FileUtil.getConfig("bg");
        if(bgs!=null){
            File file = new File(bgs);
            if(file.exists()){
                File f;
                if(file.isDirectory()){
                    File[] files = file.listFiles();
                    f = files[new Random().nextInt(files.length)];
                }else{
                    f = file;
                }
                try {
                    try (FileInputStream is = new FileInputStream(f)) {
                        Image img = new Image(is);
                        if(!img.isError()){
                            success = true;
                            bg.setImage(img);
                        }
                    }
                } catch (Exception ex) {
                    Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        if(!success){
            bg.setImage(baseBg);
        }
    }
    
    /**
     * 检查更新
     */
    @FXML
    private void checkUpdate(){
        JsonObject jo = HTTPUtil.getUpdateInfo("http://qwq.tripleying.com/others/dnfipm/version/?info");
        if(jo!=null){
            String version = jo.get("version").getAsString();
            if(App.getVersion().checkNewest(version)){
                MessageUtil.alertSimpleMessage("更新检查", "您已经是最新版本", "关闭");
            }else{
                JFXButton btn = new JFXButton("打开官网");
                btn.getStyleClass().add("dialog-accept");
                btn.setOnAction(e -> openWebsite());
                StringBuilder sb = new StringBuilder();
                sb.append("检测到新版本, 是否更新?\n")
                        .append("版本号: ").append(version).append('\n')
                        .append("更新时间: ").append(jo.get("time").getAsString()).append('\n')
                        .append("更新内容: ");
                jo.getAsJsonArray("info").forEach(i -> sb.append("\n  --").append(i.getAsString()));
                MessageUtil.alertConfirmMessage("更新检查", sb.toString(), "取消", btn);
                    // 服务器太烂! 自动下载鸽啦！！！！！
//                    new Thread(() -> {
//                        try {
//                            File file = new File(FileUtil.getFolder(), "DNFImagePacks2Manager-"+version+"-auto-update.jar");
//                            if(HTTPUtil.downloadNewFile("http://qwq.tripleying.com/others/dnfipm/files/download.php?suf=jar", file)){
//                                FileUtil.saveAppConfig(version, file);
//                                Runtime.getRuntime().exec("cmd.exe /c ping localhost -n 3 > nul&&start ../DNFImagePacks2Manager.exe", null, folder);
//                                System.exit(0);
//                            }
//                        } catch (Exception ex) {
//                            Logger.getLogger(MainController.class.getName()).log(Level.SEVERE, null, ex);
//                        }
//                    }).start();
            }
        }else{
            MessageUtil.alertSimpleMessage("更新检查失败", "连接到更新检查服务器失败", "关闭");
        }
    }
    
    @FXML
    private void press(MouseEvent e){
        x = e.getScreenX();
	y = e.getScreenY();
        x_stage = stage.getX();
        y_stage = stage.getY();
    }
    
    @FXML
    private void drag(MouseEvent e){
        stage.setX(x_stage + e.getScreenX() - x);
        if(y_stage + e.getScreenY() - y < 0) {
            stage.setY(y_stage);
        }else {
            stage.setY(y_stage + e.getScreenY() - y);
        }
    }
    
    @FXML
    private void hide(){
        stage.setIconified(true);
    }

    @FXML
    private void exit(){
        System.exit(0);
    }
    
    public void init(String title){
        this.title.setText(title);
        baseBg = bg.getImage();
        search.textProperty().addListener((ObservableValue<? extends String> observable, String oldValue, String newValue) -> {
            if(ListStatus.NPKList.equals(status) || ListStatus.NPKEmpty.equals(status)){
                searchNPK(newValue.trim());
            }
        });
        changeBackground();
        loadNPK();
    }
    
    public static MainController getInstance(){
        return mc;
    }
    
}
